package v1

import (
	"encoding/json"
	"sweetsunnyflower/app/http/dto/user"
	"sweetsunnyflower/app/models/trip_passenger"
	"sweetsunnyflower/app/models/user_passenger"
	"sweetsunnyflower/app/models/user_trip"
	"sweetsunnyflower/app/policies"
	"sweetsunnyflower/app/requests"
	"sweetsunnyflower/pkg/auth"
	"sweetsunnyflower/pkg/response"

	"github.com/gin-gonic/gin"
	"github.com/spf13/cast"
)

type TripPassengersController struct {
	Controller
}

func (ctrl *TripPassengersController) Index(c *gin.Context) {

	request := requests.TripPassengersQueryRequest{}
	if ok := requests.Validate(c, &request, requests.TripPassengersQuery); !ok {
		return
	}

	userID := auth.CurrentIntUID(c)

	request.UserID = userID

	tripPassengers := trip_passenger.GetByLatestId(request)

	userTripPassengers := make([]*user.TripPassenger, 0)

	for _, tripPassenger := range tripPassengers {

		passenger := &user.Passenger{}

		trip := &user.Trip{}

		booking := &user.Booking{}

		err := json.Unmarshal([]byte(tripPassenger.Passenger), passenger)

		if err != nil {
			response.Abort500(c, "解析乘客信息失败~")
		}

		err = json.Unmarshal([]byte(tripPassenger.Trip), trip)

		if err != nil {
			response.Abort500(c, "解析乘客行程信息失败~")
		}

		err = json.Unmarshal([]byte(tripPassenger.Booking), booking)

		if err != nil {
			response.Abort500(c, "解析乘客座位信息失败~")
		}

		format := &user.TripPassenger{
			ID:        tripPassenger.ID,
			UserID:    tripPassenger.UserID,
			TripID:    tripPassenger.TripID,
			Status:    tripPassenger.Status,
			CreatedAt: tripPassenger.CreatedAt,
			Passenger: *passenger,
			Trip:      *trip,
			Booking:   *booking,
		}

		userTripPassengers = append(userTripPassengers, format)

	}

	response.Data(c, userTripPassengers)
}

func (ctrl *TripPassengersController) Show(c *gin.Context) {
	tripPassengerModel := trip_passenger.Get(c.Param("id"))
	if tripPassengerModel.ID == 0 {
		response.Abort404(c)
		return
	}
	response.Data(c, tripPassengerModel)
}

func (ctrl *TripPassengersController) Store(c *gin.Context) {

	request := requests.TripPassengerRequest{}
	if ok := requests.Validate(c, &request, requests.TripPassengerSave); !ok {
		return
	}

	userID := auth.CurrentIntUID(c)
	// 查询行程
	trip := user_trip.Get(cast.ToString(request.TripID))

	if trip.ID == 0 {
		response.Abort404(c, "行程信息错误~")
		return
	}

	if trip.UserID == userID {
		response.Abort403(c, "自己不能参加自己的行程~")
		return
	}

	// 判断行程状态
	if trip.Status == user_trip.SUCCESS {
		response.Abort403(c, "没有剩余座位，请查看其他车辆~")
		return
	}

	if trip.Status == user_trip.CANCELLED {
		response.Abort403(c, "没有剩余座位，请查看其他车辆~")
		return
	}
	// 判断是否被司机拉黑

	// 是否已经预定
	latestTripPassenger := trip_passenger.GetByTripIdAndUserID(userID, request.TripID)
	if latestTripPassenger.ID > 0 && latestTripPassenger.Status == trip_passenger.PENDING {
		response.Abort403(c, "您已经预定，请等待确认~")
		return
	}
	// 是否有空余位置
	sumBooking, err := trip_passenger.SumBooking(trip.ID)

	if err != nil {
		response.BadRequest(c, err, "查询剩余座位失败~")
		return
	}

	remainingSites := int64(trip.Sites) - sumBooking

	if remainingSites <= 0 {
		response.Abort403(c, "没有剩余座位，请查看其他车辆~")
		return
	}

	remainingSites = remainingSites - int64(request.Booking)

	if remainingSites < 0 {
		response.Abort403(c, "座位数量不足，请查看其他车辆~")
		return
	}

	// 查询乘客信息
	passenger := user_passenger.Get(cast.ToString(request.PassengerID))

	if passenger.ID == 0 || passenger.UserID != userID {
		response.Abort404(c, "乘客信息错误~")
		return
	}

	p, err := json.Marshal(passenger)
	if err != nil {
		response.BadRequest(c, err, "查询乘客信息失败~")
		return
	}

	passengerTrip := &trip_passenger.Trip{
		ID:      trip.ID,
		UserID:  trip.UserID,
		StartID: trip.StartID,
		EndID:   trip.EndID,
		Time:    trip.Time,
		CarId:   trip.CarId,
		Sites:   trip.Sites,
		Price:   trip.Price,
		Status:  trip.Status,
		Remark:  trip.Remark,
		Line:    trip.Line,
		Start:   trip.Start,
		End:     trip.End,
		Car:     trip.Car,
	}

	t, err := json.Marshal(passengerTrip)
	if err != nil {
		response.BadRequest(c, err, "查询乘车人信息失败~")
		return
	}

	booking, err := json.Marshal(&trip_passenger.Booking{
		Sites: request.Booking,
		Price: request.Booking * trip.Price,
	})

	if err != nil {
		response.BadRequest(c, err, "查询预定信息失败~")
		return
	}

	// 更新行程剩余座位数
	trip.Remaining = uint(remainingSites)

	trip.Save()

	tripPassengerModel := trip_passenger.TripPassenger{
		TripID:    request.TripID,
		UserID:    userID,
		Status:    trip_passenger.PENDING,
		Passenger: string(p),
		Trip:      string(t),
		Booking:   string(booking),
	}

	tripPassengerModel.Create()

	if tripPassengerModel.ID > 0 {
		response.Created(c, tripPassengerModel)
	} else {
		response.Abort500(c, "创建失败，请稍后尝试~")
	}
}

func (ctrl *TripPassengersController) Update(c *gin.Context) {

	tripPassengerModel := trip_passenger.Get(c.Param("id"))
	if tripPassengerModel.ID == 0 {
		response.Abort404(c)
		return
	}

	if ok := policies.CanModifyTripPassenger(c, tripPassengerModel); !ok {
		response.Abort403(c)
		return
	}

	request := requests.TripPassengerRequest{}
	if ok := requests.Validate(c, &request, requests.TripPassengerSave); !ok {
		return
	}

	// tripPassengerModel.FieldName = request.FieldName
	rowsAffected := tripPassengerModel.Save()
	if rowsAffected > 0 {
		response.Data(c, tripPassengerModel)
	} else {
		response.Abort500(c, "更新失败，请稍后尝试~")
	}
}

func (ctrl *TripPassengersController) Delete(c *gin.Context) {

	tripPassengerModel := trip_passenger.Get(c.Param("id"))
	if tripPassengerModel.ID == 0 {
		response.Abort404(c)
		return
	}

	if ok := policies.CanModifyTripPassenger(c, tripPassengerModel); !ok {
		response.Abort403(c)
		return
	}

	rowsAffected := tripPassengerModel.Delete()
	if rowsAffected > 0 {
		response.Success(c)
		return
	}

	response.Abort500(c, "删除失败，请稍后尝试~")
}

// 同意
func (ctrl *TripPassengersController) Confirm(c *gin.Context) {
	tripPassengerModel := trip_passenger.Get(c.Param("id"))
	if tripPassengerModel.ID == 0 {
		response.Abort404(c)
		return
	}
	tripModel := user_trip.GetById(cast.ToString(tripPassengerModel.TripID))
	if ok := policies.CanModifyUserTrip(c, tripModel); !ok {
		response.Abort403(c)
		return
	}

	if tripPassengerModel.Status == trip_passenger.CONFIRMED {
		response.Success(c)
		return
	}

	if tripPassengerModel.Status != trip_passenger.PENDING {
		response.Abort403(c, "不是待确认状态，无法确认~")
		return
	}

	booking := trip_passenger.Booking{}

	// 解析预定信息
	err := json.Unmarshal([]byte(tripPassengerModel.Booking), &booking)

	if err != nil {
		response.BadRequest(c, err, "解析预定信息失败~")
		return
	}

	var remainingSites int = cast.ToInt(tripModel.Remaining) - cast.ToInt(booking.Sites)

	if remainingSites < 0 {
		response.Abort403(c, "剩余座位不足")
		return
	}

	tripModel.Remaining = cast.ToUint(remainingSites)

	// 同意
	tripPassengerModel.Status = trip_passenger.CONFIRMED
	rowsAffected := tripPassengerModel.Save()

	tripModel.Save()

	if rowsAffected > 0 {
		// 发送消息
		response.Success(c)
		return
	}
	response.Abort500(c, "更新失败，请稍后尝试~")
}

// 拒绝
func (ctrl *TripPassengersController) Refuse(c *gin.Context) {
	tripPassengerModel := trip_passenger.Get(c.Param("id"))
	if tripPassengerModel.ID == 0 {
		response.Abort404(c)
		return
	}
	tripModel := user_trip.GetById(cast.ToString(tripPassengerModel.TripID))
	if ok := policies.CanModifyUserTrip(c, tripModel); !ok {
		response.Abort403(c)
		return
	}

	if tripPassengerModel.Status == trip_passenger.REFUSE {
		response.Success(c)
		return
	}

	if tripPassengerModel.Status != trip_passenger.PENDING {
		response.Abort403(c, "不是待确认状态，无法拒绝~")
		return
	}

	// 拒绝
	tripPassengerModel.Status = trip_passenger.REFUSE
	rowsAffected := tripPassengerModel.Save()
	if rowsAffected > 0 {
		// 发送消息
		response.Success(c)
		return
	}
	response.Abort500(c, "更新失败，请稍后尝试~")
}

// 乘客取消行程
func (ctrl *TripPassengersController) Cancel(c *gin.Context) {
	tripPassengerModel := trip_passenger.Get(c.Param("id"))
	if tripPassengerModel.ID == 0 {
		response.Abort404(c)
		return
	}
	if !policies.CanModifyTripPassenger(c, tripPassengerModel) {
		response.Abort403(c)
		return
	}

	if tripPassengerModel.Status == trip_passenger.CONFIRMED {
		response.Abort403(c, "已确认的乘客不能取消~")
		return
	}

	if tripPassengerModel.Status == trip_passenger.PENDING {
		tripPassengerModel.Status = trip_passenger.CANCEL
		tripPassengerModel.Save()
		// 发送消息
		return
	}

	// 其他状态一律忽略
	response.Success(c)
}
